const {ccclass, property} = cc._decorator;


// 方块的大小
const size = 100;

const defaultGameConfig: GameConfig = {
    cardNum: 4,
    layerNum: 2,
    trap: true,
    delNode: false,
}

interface GameConfig {
    container?: cc.Node,                        // cardNode容器
    cardNum: number,                            // card类型数量
    layerNum: number                            // card层数
    trap?: boolean,                             //  是否开启陷阱
    delNode?: boolean,                          //  是否从nodes中剔除已选节点
    events?: GameEvents                         //  游戏事件
}

// 卡片节点类型
type CardNode = {
    id: string           // 节点id zIndex-index
    type: number         // 类型
    zIndex: number       // 图层
    index: number        // 所在图层中的索引
    parents: CardNode[]  // 父节点
    row: number          // 行
    column: number       // 列
    top: number
    left: number
    state: number        // 是否可点击 0： 无状态  1： 可点击 2：已选 3：已消除
}


@ccclass
export default class FlowerMain extends cc.Component {

    @property(cc.Layout)
    itemLayout: cc.Layout = null

    @property(cc.Prefab)
    block: cc.Prefab = null
    size = 100
    perFloorNodes: CardNode[] = []
    backFlag = false
    removeFlag = false
    indexSet = new Set()
    histroyList: CardNode[] = []
    nodes: CardNode[] = []
    removeList: CardNode[] = []
    selectedNodes: CardNode[] = []
    preNode: CardNode = null
    floorList: number[][] = []

    blocks = []
    resetData(){
        this.histroyList = []

        this.backFlag = false
    
        this.removeFlag = false
    
        this.removeList = []
    
        this.preNode = null
    
        this.nodes = []
    
        this.indexSet.clear()
    
        this.perFloorNodes = []
    
        this.selectedNodes = []
    
        this.floorList = []
    }
    start () {
        window.MainGame = this;
        this.initBlocks()
    }
    initBlocks() {
        this.itemLayout.enabled = true;
        // 节点数量自定义
        for(let i = 0;  i < this.row; i++){
            let blockArr = []
            for(let j = 0;  j < this.column; j++){
                let block = cc.instantiate(this.block)
                block.getComponent(ZhuanBlock).init(i, j)
                block.parent = this.itemLayout.node
                blockArr.push(block)
            }
            this.blocks.push(blockArr)
        }
        this.itemLayout.updateLayout()
        this.itemLayout.enabled = false; // 关闭布局，否则会闪烁
    }
    initData(config?: GameConfig | null) {
        const { cardNum, layerNum, trap } = { ...initConfig, ...config }
        this.resetData();
    
        const isTrap = trap && Math.floor(random(0, 100)) !== 50
    
        // 生成节点池
        const itemTypes = (new Array(cardNum).fill(0)).map((_, index) => index + 1)
        let itemList: number[] = []
        for (let i = 0; i < 3 * layerNum; i++)
            itemList = [...itemList, ...itemTypes]
    
        if (isTrap) {
            const len = itemList.length
            itemList.splice(len - cardNum, len)
        }
        // 打乱节点
        itemList = shuffle(shuffle(itemList))
    
        // 初始化各个层级节点
        let len = 0
        let floorIndex = 1
        const itemLength = itemList.length
        while (len <= itemLength) {
            const maxFloorNum = floorIndex * floorIndex
            const floorNum = Math.ceil(random(maxFloorNum / 2, maxFloorNum))
            this.floorList.push(itemList.splice(0, floorNum))
            len += floorNum
            floorIndex++
        }
    
    
        const containerWidth = container.value!.clientWidth
        const containerHeight = container.value!.clientHeight
        const width = containerWidth / 2
        const height = containerHeight / 2 - 60
    
        this.floorList.forEach((o, index) => {
            this.indexSet.clear()
            let i = 0
            const floorNodes: CardNode[] = []
            o.forEach((k) => {
                i = Math.floor(random(0, (index + 1) ** 2))
                while (this.indexSet.has(i))
                    i = Math.floor(random(0, (index + 1) ** 2))
                const row = Math.floor(i / (index + 1))
                const column = index ? i % index : 0
                const node: CardNode = {
                    id: `${index}-${i}`,
                    type: k,
                    zIndex: index,
                    index: i,
                    row,
                    column,
                    top: height + (size * row - (size / 2) * index),
                    left: width + (size * column - (size / 2) * index),
                    parents: [],
                    state: 0,
                }
                const xy = [node.top, node.left]
                // 根据位置判断不超过元素本身的大小就认为叠在一起
                this.perFloorNodes.forEach((e: CardNode) => {
                    if (Math.abs(e.top - xy[0]) <= size && Math.abs(e.left - xy[1]) <= size)
                        e.parents.push(node)
                })
                this.floorNodes.push(node)
                this.indexSet.add(i)
            })
            this.nodes = this.nodes.concat(this.floorNodes)
            this.perFloorNodes = this.floorNodes
        })
    
        this.updateState()
    }
    updateState() {
        this.nodes.forEach((o: CardNode) => {
            o.state = o.parents.every(p => p.state > 0) ? 1 : 0
        })
    }
    // update (dt) {}
}


const freeParseFloat = parseFloat

function random(lower, upper, floating?) {
    if (floating === undefined) {
        if (typeof upper === 'boolean') {
            floating = upper
            upper = undefined
        }
        else if (typeof lower === 'boolean') {
            floating = lower
            lower = undefined
        }
    }
    if (lower === undefined && upper === undefined) {
        lower = 0
        upper = 1
    }
    else {
        lower = toFinite(lower)
        if (upper === undefined) {
            upper = lower
            lower = 0
        } else {
            upper = toFinite(upper)
        }
    }
    if (lower > upper) {
        const temp = lower
        lower = upper
        upper = temp
    }
    if (floating || lower % 1 || upper % 1) {
        const rand = Math.random()
        const randLength = `${rand}`.length - 1
        return Math.min(lower + (rand * (upper - lower + freeParseFloat(`1e-${randLength}`))), upper)
    }
    return lower + Math.floor(Math.random() * (upper - lower + 1))
}